home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / bss / pup.arc / MSGBASE.C < prev    next >
C/C++ Source or Header  |  1987-12-11  |  7KB  |  281 lines

  1. #include <puppy.h>
  2. #include <pupmem.h>
  3. #include <ascii.h>
  4.  
  5. /*
  6.     Message Base functions
  7.  
  8.     Tom Jennings
  9.     20 Sept 87
  10.  
  11.  
  12. This is the message base (its too crude to be called a "database") for
  13. Puppy. 
  14.  
  15. To the user, it appears to be a Pile of messages of fixed length. You
  16. start at the top of the pile, and read messages one by one until you
  17. hit the bottom. When a new message is enter, it goes on the Top of the
  18. pile and the oldest one falls off the bottom.
  19.  
  20. Physically this is of course a linear file, and is implemented as a
  21. "ring buffer". There is a "place keeper" counter called the "top". 
  22. Initially, the message base is empty, and the top is the beginning
  23. of the file. 
  24.  
  25. It is the nature of this ring buffer that since the "top" points to 
  26. the newest record, (top - 1) is therefore the oldest record. This is
  27. the feature the whole thing is based on. (top - 1) is called the "bottom".
  28.  
  29. (When Top excrements beyond the end or beginning of the physical file,
  30. it is wrapped to the opposite end as you might expect.)
  31.  
  32. When a new message is entered, it is stored at the bottom, ie. in the
  33. oldest record. The top is then decremented so that it points to the
  34. new record; this was the oldest, and now is the newest. The previous
  35. newest is now 2nd newest, etc.
  36.  
  37.  
  38. The interface to this module is the "message number". Message numbers
  39. run 1 (newest, Top of the pile) to N (oldest, bottom of the pile.)
  40.  
  41.  
  42. Internally of course we gotta deal in records, which get converted
  43. into a byte file position. Conversion from MessageNumber to Record is:
  44.  
  45.     recd= (MessageNumber + Top) % pup.Messages
  46.  
  47. */
  48.  
  49.  
  50. /*
  51.  
  52. openmsg()    Open/start the message base.
  53. closemsg()    Close the message base.
  54.  
  55. Frequently used message base primitives
  56.  
  57. recd(n)        Converts message number into record number.
  58. getmsg(n)    Returns a pointer to message header #n.
  59. ismsg(n,t)    Returns true if the specified message number exists and
  60.         matches the selected topics.
  61.  
  62. Various message characteristic routines
  63.  
  64. highmsg()    Returns the highest message number.
  65. newmsg()    Returns a pointer to the next free message
  66.         header structure.
  67. killmsg(n)    Marks a message as deleted.
  68.  
  69. Message data manipulation routines
  70.  
  71. savemsg(lines)    Add the message in memory to the file.
  72. loadmsg(n)    Load message #n into the text buffer.
  73.  
  74. Message display routines
  75.  
  76. topics(t)    List the topics specified in the bit field.
  77. listhdr(n)    Displays the contents of message header #N.
  78. listmsg(n)    Displays the contents of the message body.
  79. */
  80.  
  81. /* Open the message base; open both files, load the index. */
  82.  
  83. openmsg() {
  84.  
  85.     msgfile= open("message.idx",2);        /* open the msg base */
  86.     txtfile= open("message.dat",2);
  87.     if ((msgfile < 0) || (txtfile < 0)) {
  88.         printf("Message base file(s) missing!\r\n");
  89.  
  90.     } else read(msgfile,msg,pup.messages * sizeof(struct _msg));
  91. }
  92.  
  93. /* Close the message base. */
  94.  
  95. closemsg() {
  96.  
  97.     if (msgfile != -1) close(msgfile);
  98.     if (txtfile != -1) close(txtfile);
  99.     msgfile= txtfile= -1;
  100. }
  101.  
  102. /* Say which message this is. It says "top" for the bottom message
  103. because thats where new messages go before they are saved. */
  104.  
  105. fromtop(n)
  106. int n;
  107. {
  108.     if ((n == 1) || (n == highmsg())) mputs("AT");
  109.     else mprintf("%d DOWN FROM",n - 1);
  110.     mputs(" THE TOP\r\n");
  111. }
  112.  
  113. /* Expand the topics bit field into topic names. Handle the special
  114. case NONE. */
  115.  
  116. topics(t)
  117. WORD t;
  118. {
  119. int i,n;
  120.  
  121.     n= 0;
  122.     for (i= 0; i < 16; i++) {
  123.         if ((t & (1 << i)) && *pup.topic[i].name) {
  124.             mprintf(" %s",pup.topic[i].name);
  125.             ++n;
  126.         }
  127.     }
  128.     if (! n) mputs(" NONE");
  129. }
  130.  
  131. /* List message header #n. */
  132.  
  133. listhdr(n)
  134. int n;
  135. {
  136. struct _msg *t;
  137. char *sep;
  138.  
  139.     sep= ", ";                    /* assume wide screen */
  140.     if (width < 80) sep= "\r\n";            /* if not, break into 5 lines */
  141.     t= getmsg(n);                    /* ptr to this message */
  142.     fromtop(n);                    /* "N from the top" */
  143.  
  144.     mprintf("FROM: %s%s",t-> from,sep);        /* FROM name, space or CR */
  145.     mprintf("TO: %s%s",t-> to,sep);            /* TO name, space or CR */
  146.     mprintf("%d-%d-%d\r\n",t-> time.month,t-> time.day,t-> time.year);
  147.  
  148.     mputs("TOPIC:"); topics(t-> topic); mputs(sep); 
  149.     mprintf("TITLE: %s\r\n",t-> subj);
  150. }
  151.  
  152. /* Display the body of a message. This just seeks to the right
  153. place in the file and dumps the text. */
  154.  
  155. listmsg(n)
  156. int n;
  157. {
  158. long l;
  159.  
  160.     l= 0L + pup.msgsize;
  161.     l *= (long) recd(n);
  162.     lseek(txtfile,l,0);
  163.     dumptext(txtfile);
  164. }
  165.  
  166. /* ---------------------------------------------------------------- */
  167.  
  168. /* Return true if this message number exists and is part of 
  169. the selected topic(s). */
  170.  
  171. ismsg(n,t)
  172. int n;
  173. {
  174.     if (n > highmsg()) return(0);        /* too high! */
  175.     if (n < 1) return(0);            /* too low! */
  176.  
  177.     return((getmsg(n)-> attr & MSGEXISTS)    /* check exists */
  178.       && (getmsg(n)-> topic & t));        /* and topics match */
  179. }
  180.  
  181. /* Mark this message as deleted. */
  182.  
  183. killmsg(n)
  184. int n;
  185. {
  186.     if (ismsg(n,-1)) getmsg(n)-> attr &= ~MSGEXISTS;
  187. }
  188.     
  189. /* Convert message number (1 - N) into record number (0 - N). */
  190.  
  191. recd(n)
  192. int n;
  193. {
  194. int i;
  195.     i= ((n - 1 + pup.top) % pup.messages);
  196.     return(i);
  197. }
  198.  
  199. /* Return the highest message (bottom message) number. (They run 1 - N) */
  200.  
  201. highmsg() {
  202.  
  203.     return(pup.messages);
  204. }
  205.  
  206. /* Return a pointer to message header #n. */
  207.  
  208. struct _msg *getmsg(n)
  209. {
  210.     return(&msg[recd(n)]);
  211. }
  212.  
  213. /* Return a pointer to the next free message header. */
  214.  
  215. struct _msg *newmsg() {
  216.  
  217.     return(getmsg(highmsg()));
  218. }
  219.  
  220. /* Add this message to the message file. Since the message header is
  221. created in the bottom message header in the array, advancing it is the
  222. same as saving it. The message body must be written out however. Since 
  223. the file is preallocated, we dont have to check for write errors. (right) */
  224.  
  225. savemsg(lines)
  226. int lines;
  227. {
  228. int n,i;
  229. char *cp;
  230. long o;
  231.  
  232.     if (--pup.top < 0) 
  233.         pup.top= pup.messages - 1;    /* next message ... */
  234.     ++pup.msgnbr;                /* another message ... */
  235.  
  236.     msg[pup.top].attr |= MSGEXISTS;        /* new message */
  237.     msg[pup.top].topic_map= 0;        /* clear the map */
  238.     writehdr(pup.top);            /* write out the msg header, */
  239.  
  240. /* We must write out exactly (msgsize) bytes. */
  241.  
  242.     o= 0L + pup.top;
  243.     o *= pup.msgsize;
  244.     lseek(txtfile,o,0);
  245.     for (n= i= 0; i < lines; i++) {
  246.         cp= &text[i * width];        /* write each line of text */
  247.         write(txtfile,cp,strlen(cp));
  248.         n += strlen(cp);        /* bozo check: dont exceed max */
  249.         if (n >= pup.msgsize - 1) break;/* plus room for a terminator */
  250.     }
  251.  
  252.     n= pup.msgsize - n;            /* amt we need to fill out msg */
  253.     cp= text; for (i= n; i--;) *cp++= SUB;    /* fill with ^Zs */
  254.     write(txtfile,text,n);            /* pad it out */
  255. }
  256.  
  257. /* Write out the specified message header record. */
  258.  
  259. writehdr(n)
  260. int n;
  261. {
  262. long o;
  263.     o= 0L + n;
  264.     o *= sizeof(struct _msg);
  265.     lseek(msgfile,o,0);
  266.     write(msgfile,&msg[n],sizeof(struct _msg));
  267. }
  268.  
  269. /* Load message body #n into the text buffer. */
  270.  
  271. loadmsg(n)
  272. int n;
  273. {
  274. long o;
  275.  
  276.     o= 0L + recd(n);
  277.     o *= pup.msgsize;
  278.     lseek(txtfile,o,0);
  279.     read(txtfile,text,pup.msgsize);
  280. }
  281.